﻿/*+===================================================================
File:      PlayState.cpp

Summary:   Định nghĩa các phương thức của CPlayState.
===================================================================+*/

#include "PlayState.h"
#include "ItemBlock.h"
#include "EnemySniper.h"
#include "EnemyShelter.h"
#include "GunBlock.h"
#include "GunMachine.h"
#include "BossOne.h"
#include "StoneFlying.h"
#include "StoneFallingPoint.h"
#include "Fire.h"
#include "EnemyDiver.h"
#include "EnemyMachine.h"
#include "Grenade.h"
#include "Tank.h"
#include "BossThreeChild.h"
#include "BossThreeDoor.h"
#include "BossTwo.h"
#include <stdexcept>

CGameObject* CPlayState::m_pObjBoss;
vector<CBullet*> CPlayState::s_billBullets;
vector<CBullet*> CPlayState::s_enemyBullets;
CRunningMan* CPlayState::s_enemyRun[MAX_ENEMIES];
vector<CGameObject*> CPlayState::s_objsOutSideQuadTree;

CPlayState::CPlayState()
{
	Init();
}

CPlayState::~CPlayState()
{
	if (m_pBill)
		delete m_pBill;
	if (m_pEnemyRun)
		delete m_pEnemyRun;
	if (m_pResourcesManager)
		delete m_pResourcesManager;
	if (m_pRootNode)
		delete m_pRootNode;
	if (m_pCollisionNode)
		delete m_pCollisionNode;
	if (m_pShader)
		delete m_pShader;
	if (m_pSound)
		delete m_pSound;
	for (map<int, CGameObject*>::iterator it = m_aGameObject.begin(); it != m_aGameObject.end(); ++it)
	{
		if (it->second)
			delete it->second;
	}
	for (map<int, CGameObject*>::iterator it = m_aBGameObject.begin(); it != m_aBGameObject.end(); ++it)
	{
		if (it->second)
			delete it->second;
	}
	for (int i = 0; i < m_aObjectToDraw.size(); i++)
	{
		if (m_aObjectToDraw[i])
			delete m_aObjectToDraw[i];
	}
	for (int i = 0; i < m_aObjectToCollision.size(); i++)
	{
		if (m_aObjectToCollision[i])
			delete m_aObjectToCollision[i];
	}
}

void CPlayState::LoadMap()
{
#pragma region Chọn level
	string mapPath;
	switch (g_nCurentLvl)
	{
	case ID_LEVEL1:
		mapPath = MAP1_PATH;
		m_pTexture = m_pResourcesManager->GetTexture(ID_TEXTURE_MAP1_TILES);
		break;
	case ID_LEVEL2:
		mapPath = MAP2_PATH;
		m_pTexture = m_pResourcesManager->GetTexture(ID_TEXTURE_MAP2_TILES);
		break;
	case ID_LEVEL3:
		mapPath = MAP3_PATH;
		m_pTexture = m_pResourcesManager->GetTexture(ID_TEXTURE_MAP3_TILES);
		break;
	}
#pragma endregion
#pragma region Khai báo các biến tạm
	//Luồng đọc file map
	ifstream mapData;
	//Chuỗi đọc file Map
	string text;

	// Mở file map.
	mapData.open(mapPath, ios::in);

	//Kiểm tra không mở được file
	if (!mapData.is_open())
	{
		OutputDebugString("[map.cpp] Can not open map file.");
		return;
	}
	//Luồng string đọc file map
	istringstream iss(text);

	//Các biến tạm lưu thông tin map
	int stageNum, tileNum, tileSize, objNum, bodyNum;

	//Các biến tạm lưu vị trí map
	float posx, posy;

	//Các biến lưu số hàng và số cột ma trận tile
	int tileRow, tileCol;

	//Biến lưu các giá trị của hình tile
	int picCol = m_pTexture->m_nCols;

	//Các biến tạm lưu dữ liệu của node quadtree vẽ
	int nId, x1, y1, w, h, nNum, oNum, gOId;
	vector<int> gameObjectId;

	//map node quadtree vẽ lưu tạm
	map<int, CQNode*> listQNode;

	//Node quadtree vẽ lưu tạm
	CQNode* tmpNode = NULL;

	//Biến lưu dữ liệu body của quadtree va chạm
	int bId, bType, bX, bY, bW, bH;
	//Biến lưu số lượng body của mỗi node của quadtree va chạm
	int bNum;
	//Biến tạm lưu danh sách các bodyId của quadtree va chạm
	vector<int> gameBodyId;

	//Biến tạm lưu dữ liệu game object
	int oId, oType, oX, oY, oBody, oVal1, oVal2;
	//Biến gameobject tạm
	CGameObject* tmpObject;
	//Map node quadtree va chạm lưu tạm
	map<int, CQNode*> listCNode;


#pragma endregion
	while (getline(mapData, text))
	{
#pragma region Đọc phần Header
		if (text.compare("HEADER") == 0)
		{
			getline(mapData, text);
			getline(mapData, text);
			getline(mapData, text);
			iss.clear();
			iss.str(text);
			iss >> stageNum >> tileNum >> tileSize >> objNum >> bodyNum;
			getline(mapData, text);
			getline(mapData, text);
			getline(mapData, text);
			getline(mapData, text);
			iss.clear();
			iss.str(text);
			iss >> posx >> posy >> tileCol >> tileRow;
		}
		m_nMapWidth = tileCol * tileSize;
		m_nMapHeight = tileRow * tileSize;
		m_nTileSize = tileSize;
#pragma endregion
#pragma region Đọc ma trận state và ma trận body
		if (text.compare("STATE_SET") == 0)
		{
			getline(mapData, text);
			iss.clear();
			iss.str(text);
			for (int i = 0; i < tileRow; i++)
			{
				vector<int> tmp;
				tmp.resize(tileCol);
				m_aMatrixTile.push_back(tmp);
			}
			//Đưa dữ liệu vào mảng tile
			//Biến lưu đối tượng game tạm
			CGameObject* tmpGameObject = NULL;
			int k, m, n;
			switch (g_nCurentLvl)
			{
			case ID_LEVEL1:
			case ID_LEVEL3:
				for (int i = 0; i < tileRow; i++)
				{
					getline(mapData, text);
					iss.clear();
					iss.str(text);
					for (int j = 0; j < tileCol; j++)
					{
						iss >> m_aMatrixTile[i][j];
						k = m_aMatrixTile[i][j];
						m = k % picCol;
						n = k / picCol;
						D3DXVECTOR2 pos(
							(float)j * tileSize + tileSize / 2,
							SCREEN_HEIGHT - ((float)i * tileSize) - tileSize);
						RECT r =
						{
							m * tileSize,
							n * tileSize,
							m * tileSize + tileSize,
							n * tileSize + tileSize
						};
						tmpGameObject = new CTileObject(pos, i * tileCol + j, ID_TILE, r, g_nCurentLvl);
						m_aGameObject.insert(pair<int, CGameObject*>(i * tileCol + j, tmpGameObject));
					}
				}
				break;
			case ID_LEVEL2:
				for (int i = 0; i < tileRow; i++)
				{
					getline(mapData, text);
					iss.clear();
					iss.str(text);
					for (int j = 0; j < tileCol; j++)
					{
						iss >> m_aMatrixTile[i][j];
						k = m_aMatrixTile[i][j];
						m = k % picCol;
						n = k / picCol;
						D3DXVECTOR2 pos(
							(float)j * tileSize + tileSize / 2,
							tileRow * tileSize - ((float)i * tileSize) - tileSize / 2);
						RECT r =
						{
							m * tileSize,
							n * tileSize,
							m * tileSize + tileSize,
							n * tileSize + tileSize
						};
						tmpGameObject = new CTileObject(pos, i * tileCol + j, ID_TILE, r, g_nCurentLvl);
						m_aGameObject.insert(pair<int, CGameObject*>(i * tileCol + j, tmpGameObject));
					}
				}
				break;
			default:
				break;
			}
		}
#pragma endregion
#pragma region Đọc danh sách object và body
		if (text.compare("OBJECT_LIST") == 0)
		{
			getline(mapData, text);
			getline(mapData, text);
			while (text.compare("END_OBJECT_LIST") != 0)
			{
				iss.clear();
				iss.str(text);
				iss >> oId >> oType >> oX >> oY >> oBody >> oVal1 >> oVal2;
				switch (oType)
				{
				case ID_ENEMY_SHELTER:
					tmpObject = new CEnemyShelter(m_pBill, D3DXVECTOR2((float)oX, (float)oY),
						oId, ID_ENEMY_SHELTER);
					tmpObject->m_nBoxId = oBody;
					m_aGameObject.insert(pair<int, CGameObject*>(oId, tmpObject));
					break;
				case ID_ENEMY_SNIPER:
					tmpObject = new CEnemySniper(m_pBill, D3DXVECTOR2((float)oX, (float)oY),
						oId, ID_ENEMY_SNIPER);
					tmpObject->m_nBoxId = oBody;
					m_aGameObject.insert(pair<int, CGameObject*>(oId, tmpObject));
					break;
				case ID_BRIDGE:
					tmpObject = new CBridge(m_pBill, D3DXVECTOR2((float)oX, (float)oY),
						oId, ID_BRIDGE);
					tmpObject->m_nBoxId = oBody;
					m_aGameObject.insert(pair<int, CGameObject*>(oId, tmpObject));
					break;
				case ID_ITEM_FLYING:
					tmpObject = new CFlyItemBound(m_pBill, D3DXVECTOR2((float)oX, (float)oY), oId,
						ID_ITEM_FLYING, oVal1);
					tmpObject->m_nBoxId = oBody;
					m_aGameObject.insert(pair<int, CGameObject*>(oId, tmpObject));
					m_pResourcesManager->GetSprite(ID_SPRITE_STONE_FLYING);
					break;
				case ID_ITEM_BLOCK:
					tmpObject = new CItemBlock(m_pBill, D3DXVECTOR2((float)oX, (float)oY), oId,
						ID_ITEM_BLOCK, oVal1);
					tmpObject->m_nBoxId = oBody;
					m_aGameObject.insert(pair<int, CGameObject*>(oId, tmpObject));
					m_pResourcesManager->GetSprite(ID_SPRITE_FLY_ITEM);
					break;
				case ID_GUN_BLOCK:
					tmpObject = new CGunBlock(m_pBill, D3DXVECTOR2((float)oX, (float)oY), oId,
						ID_GUN_BLOCK);
					tmpObject->m_nBoxId = oBody;
					m_aGameObject.insert(pair<int, CGameObject*>(oId, tmpObject));
					break;
				case ID_GUN_MACHINE:
					tmpObject = new CGunMachine(m_pBill, D3DXVECTOR2((float)oX, (float)oY), oId,
						ID_GUN_MACHINE);
					tmpObject->m_nBoxId = oBody;
					m_aGameObject.insert(pair<int, CGameObject*>(oId, tmpObject));
					break;
				case ID_RUNNING_MAN:
					tmpObject = new CRunningMan(D3DXVECTOR2((float)oX, (float)oY), oId,
						ID_RUNNING_MAN, oVal1);
					tmpObject->m_nBoxId = oBody;
					m_aGameObject.insert(pair<int, CGameObject*>(oId, tmpObject));
					m_aGameObject.insert(pair<int, CGameObject*>(oId, tmpObject));
					break;
				case ID_STONE_FALLING_POINT:
					tmpObject = new CStoneFallingPoint(D3DXVECTOR2((float)oX, (float)oY), oId,
						ID_STONE_FALLING_POINT);
					tmpObject->m_nBoxId = oBody;
					m_aGameObject.insert(pair<int, CGameObject*>(oId, tmpObject));
					break;
				case ID_STONE_FLYING:
					tmpObject = new CStoneFlying(D3DXVECTOR2((float)oX, (float)oY), oId,
						ID_STONE_FLYING);
					tmpObject->m_nBoxId = oBody;
					m_aGameObject.insert(pair<int, CGameObject*>(oId, tmpObject));
					m_pResourcesManager->GetSprite(ID_SPRITE_STONE_FLYING);
					break;
				case ID_FIRE:
					tmpObject = new CFire(D3DXVECTOR2((float)oX, (float)oY), oId,
						ID_FIRE, oVal1);
					tmpObject->m_nBoxId = oBody;
					m_aGameObject.insert(pair<int, CGameObject*>(oId, tmpObject));
					m_pResourcesManager->GetSprite(ID_SPRITE_FIRE);
					break;
				case ID_ENEMY_DIVER:
					tmpObject = new CEnemyDiver(m_pBill, D3DXVECTOR2((float)oX, (float)oY), oId,
						ID_ENEMY_DIVER);
					tmpObject->m_nBoxId = oBody;
					m_aGameObject.insert(pair<int, CGameObject*>(oId, tmpObject));
					break;
				case ID_ENEMY_MACHINE:
					tmpObject = new CEnemyMachine(D3DXVECTOR2((float)oX, (float)oY), oId,
						ID_ENEMY_MACHINE);
					tmpObject->m_nBoxId = oBody;
					m_pResourcesManager->GetSprite(ID_SPRITE_ENEMY_MACHINE_STAND);
					m_pResourcesManager->GetSprite(ID_SPRITE_ENEMY_MACHINE_FIRE);
					m_aGameObject.insert(pair<int, CGameObject*>(oId, tmpObject));
					break;
				case ID_GRENADE:
					tmpObject = new CGrenade(D3DXVECTOR2((float)oX, (float)oY), oId,
						ID_GRENADE);
					tmpObject->m_nBoxId = oBody;
					m_aGameObject.insert(pair<int, CGameObject*>(oId, tmpObject));
					break;
				case ID_TANK:
					tmpObject = new CTank(m_pBill, D3DXVECTOR2((float)oX, (float)oY), oId,
						ID_TANK);
					tmpObject->m_nBoxId = oBody;
					m_aGameObject.insert(pair<int, CGameObject*>(oId, tmpObject));
					break;
				default:
					break;
				}
				getline(mapData, text);
			}
		}
		if (text.compare("BODY_LIST") == 0)
		{
			getline(mapData, text);
			getline(mapData, text);
			std::map<int, CGameObject*>::iterator iter;
			while (text.compare("END_BODY_LIST") != 0){
				iss.clear();
				iss.str(text);
				iss >> bId >> bType >> bX >> bY >> bW >> bH;
				if (bType < 10)
				{
					/*if (bId == 39)
						output_print("");*/
					tmpObject = new CStaticObject(D3DXVECTOR2(bX, bY), bId, bType);
					Box box = { (float)bX, (float)bY, (float)bW, (float)bH, 0, 0 };
					tmpObject->SetBoundBox(box);
					m_aBGameObject.insert(pair<int, CGameObject*>(bId, tmpObject));
				}
				else
				{
					Box box = { (float)bX, (float)bY, (float)bW, (float)bH, 0, 0 };
					for (iter = m_aGameObject.begin(); iter != m_aGameObject.end(); iter++)
					{
						if (bId == iter->second->m_nBoxId)
						{
							iter->second->m_box = box;
							m_aBGameObject.insert(pair<int, CGameObject*>(bId, iter->second));
						}
					}
				}
				getline(mapData, text);
			}
		}
#pragma endregion
#pragma region Đọc quadtree vẽ
		if (text.compare("QUAD_TREE_DRAW") == 0)
		{
			getline(mapData, text);
			while (text.compare("END_QUAD_TREE_DRAW") != 0){
				getline(mapData, text);
				iss.clear();
				iss.str(text);
				iss >> nId >> x1 >> y1 >> w >> h >> nNum >> oNum;
				for (int i = 0; i < oNum; i++)
				{
					iss >> gOId;
					gameObjectId.push_back(gOId);
				}
				tmpNode = new CQNode(nId, x1, y1, x1 + w, y1 - h, gameObjectId, m_aGameObject);
				listQNode.insert(pair<int, CQNode*>(nId, tmpNode));
				gameObjectId.clear();
			}
		}

#pragma endregion
#pragma region Đọc quadtree va chạm
		if (text.compare("QUAD_TREE_COLLISION") == 0)
		{
			getline(mapData, text);
			while (text.compare("END_QUAD_TREE_COLLISION") != 0){
				getline(mapData, text);
				iss.clear();
				iss.str(text);
				iss >> nId >> x1 >> y1 >> w >> h >> nNum >> bNum;
				/*if (nId == 4)
					output_print("");*/
				for (int i = 0; i < bNum; i++)
				{
					iss >> bId;
					gameBodyId.push_back(bId);
				}
				tmpNode = new CQNode(nId, x1, y1, x1 + w, y1 - h, gameBodyId, m_aBGameObject);
				listCNode.insert(pair<int, CQNode*>(nId, tmpNode));
				gameBodyId.clear();
			}
		}
#pragma endregion
#pragma region Kết thúc đọc file Map
		if (text.compare("END_QUAD_TREE_COLLISION") == 0)
		{
			break;
		}
#pragma endregion
	}
	mapData.close();
#pragma region Thêm các object vào các node trong quadtree vẽ
	map<int, CQNode*>::iterator it;
	map<int, CQNode*>::iterator findResult;
	for (it = listQNode.begin(); it != listQNode.end(); it++)
	{
		int currentNodeID = it->first;
		// Node trái trên
		findResult = listQNode.find(currentNodeID * 8 + 1);
		if (findResult != listQNode.end())
		{
			it->second->AddNodeLT(findResult->second);
		}

		// Node phải listQNode
		findResult = listQNode.find(currentNodeID * 8 + 2);
		if (findResult != listQNode.end())
		{
			it->second->AddNodeRT(findResult->second);
		}

		// Node trái dưới
		findResult = listQNode.find(currentNodeID * 8 + 3);
		if (findResult != listQNode.end())
		{
			it->second->AddNodeLB(findResult->second);
		}

		// Node phải dưới
		findResult = listQNode.find(currentNodeID * 8 + 4);
		if (findResult != listQNode.end())
		{
			it->second->AddNodeRB(findResult->second);
		}

		findResult = listQNode.find(0);
		m_pRootNode = findResult->second;
	}
#pragma endregion
#pragma region Thêm các object vào các node trong quadtree va chạm
	for (it = listCNode.begin(); it != listCNode.end(); it++)
	{
		int currentNodeID = it->first;
		// Node trái trên
		findResult = listCNode.find(currentNodeID * 8 + 1);
		if (findResult != listCNode.end())
		{
			it->second->AddNodeLT(findResult->second);
		}

		// Node phải trên
		findResult = listCNode.find(currentNodeID * 8 + 2);
		if (findResult != listCNode.end())
		{
			it->second->AddNodeRT(findResult->second);
		}

		// Node trái dưới
		findResult = listCNode.find(currentNodeID * 8 + 3);
		if (findResult != listCNode.end())
		{
			it->second->AddNodeLB(findResult->second);
		}

		// Node phải dưới
		findResult = listCNode.find(currentNodeID * 8 + 4);
		if (findResult != listCNode.end())
		{
			it->second->AddNodeRB(findResult->second);
		}

		findResult = listCNode.find(0);
		m_pCollisionNode = findResult->second;
	}
#pragma endregion
}

void CPlayState::Init()
{
	//Khởi tạo pixelshader
	m_pDevice = CGraphic::GetInstance()->GetDevice();
	m_pShader = CGraphic::GetInstance()->texPS;
	m_fTimeLocal = 0.0f;
	m_fTimeEnd = 2.0f;

	//Khởi tạo đối tượng quản lý tài nguyên
	m_pResourcesManager = CResourcesManager::GetInstance();

	CGameObject::m_pResourceManager = m_pResourcesManager;

	m_pResourcesManager->GetSprite(ID_SPRITE_SMALL_EXPLOSION);
	m_pResourcesManager->GetSprite(ID_SPRITE_BIG_EXPLOSION);
	m_pResourcesManager->GetSprite(ID_SPRITE_ENEMY_EXPLOSION);
	m_pResourcesManager->GetSprite(ID_SPRITE_ENEMY_SMALL_RED_BULLET);
	m_pResourcesManager->GetSprite(ID_SOUND_OP_THEME);
	m_pResourcesManager->GetSprite(ID_SOUND_LEVEL1_THEME);
	m_pResourcesManager->GetSprite(ID_SOUND_LEVEL2_THEME);
	m_pResourcesManager->GetSprite(ID_SOUND_LEVEL3_THEME);
	m_pResourcesManager->GetSprite(ID_SOUND_END_THEME);
	m_pResourcesManager->GetSprite(ID_SOUND_CONTRA_FIRE);
	m_pResourcesManager->GetSprite(ID_SOUND_CONTRA_DEAD);
	m_pResourcesManager->GetSprite(ID_SOUND_FALL);
	m_pResourcesManager->GetSprite(ID_SOUND_GUN_UP);
	m_pResourcesManager->GetSprite(ID_SOUND_BOSS_DEAD);
	m_pResourcesManager->GetSprite(ID_SOUND_GAME_OVER_THEME);
	m_pResourcesManager->GetTexture(ID_TEXTURE_BILL);
	m_pResourcesManager->GetTexture(ID_TEXTURE_MAP1_TILES);
	m_pResourcesManager->GetTexture(ID_TEXTURE_MAP2_TILES);
	m_pResourcesManager->GetTexture(ID_TEXTURE_MAP3_TILES);
	m_pResourcesManager->GetTexture(ID_TEXTURE_MENU_BACKGROUND);
	m_pResourcesManager->GetTexture(ID_TEXTURE_PLAYER1_TEXTURE);
	m_pResourcesManager->GetTexture(ID_TEXTURE_CHOOSE_BUTTON);
	m_pResourcesManager->GetTexture(ID_TEXTURE_LIFE);
	

	CPlayState::s_objsOutSideQuadTree.clear();
	CPlayState::s_billBullets.clear();
	CPlayState::s_enemyBullets.clear();

	m_pBill = new CBill(D3DXVECTOR2(5000, 400), ID_BILL, 100);

	this->LoadMap();
	switch (g_nCurentLvl)
	{
	case ID_LEVEL1:
		if (!CGraphic::GetInstance()->InitPixelShader(HLSL1_PATH))
		{
			OutputDebugString("[Game.cpp] Cannot init pixel shader.");
		}
		m_pSound = m_pResourcesManager->GetSound(ID_SOUND_LEVEL1_THEME);
		m_pBill->m_pos = D3DXVECTOR2(200, 400);
		CViewport::GetInstance()->SetLimitPos(m_nMapWidth, m_nMapHeight);
		m_pObjBoss = new CBossOne(m_pBill, D3DXVECTOR2(6544, 192), 0, ID_BOSS_ONE);
		break;
	case ID_LEVEL2:
		if (!CGraphic::GetInstance()->InitPixelShader(HLSL2_PATH))
		{
			OutputDebugString("[Game.cpp] Cannot init pixel shader.");
		}
		m_pSound = m_pResourcesManager->GetSound(ID_SOUND_LEVEL2_THEME);
		m_pBill->m_pos = D3DXVECTOR2(200, 200);
		//m_pBill->m_pos = D3DXVECTOR2(200, 3700);
		m_pObjBoss = new CBossTwo(m_pBill, D3DXVECTOR2(320, 4125), 0, ID_BOSS_TWO);
		CViewport::GetInstance()->SetLimitPos(m_nMapWidth - m_nTileSize, m_nMapHeight + 600);
		break;
	case ID_LEVEL3:
		if (!CGraphic::GetInstance()->InitPixelShader(HLSL3_PATH))
		{
			OutputDebugString("[Game.cpp] Cannot init pixel shader.");
		}
		m_pBill->m_pos = D3DXVECTOR2(200, 400);
		//m_pBill->m_pos = D3DXVECTOR2(3300, 400);
		m_pSound = m_pResourcesManager->GetSound(ID_SOUND_LEVEL3_THEME);
		m_pObjBoss = new CBossThreeDoor(D3DXVECTOR2(10112, 192), 0, ID_BOSS_THREE_DOOR);
		CViewport::GetInstance()->SetLimitPos(m_nMapWidth, m_nMapHeight);
		break;
	}
	if (!m_pSound->IsSoundPlaying())
		m_pSound->Play();
	m_pResourcesManager->GetSound(ID_SOUND_BOSS_DEAD);
	
	m_pEnemyRun = new CEnemyRun(m_pBill);
	m_pLifeTexture = m_pResourcesManager->GetTexture(ID_TEXTURE_LIFE);
	m_bChanged = false;
	m_fTimeChange = 2.0f;
}

void CPlayState::Update(float deltaTime)
{
	if (m_bFinished)
		return;

	if (CInput::GetInstance()->IsKeyPress(DIK_6))
	{
		g_nCurentLvl = 0;
		this->End();
	}

	if (CInput::GetInstance()->IsKeyPress(DIK_7))
	{
		g_nCurentLvl = 1;
		this->End();
	}

	if (CInput::GetInstance()->IsKeyPress(DIK_8))
	{
		g_nCurentLvl = 2;
		this->End();
	}


	//Update Pixel shader
	m_fTimeLocal += deltaTime;
	if (m_fTimeLocal >= 0.4f)
	{
		m_fTimeLocal = 0.0f;
	}

	//Kiểm tra hết mạng thì trả qua GameOverState
	if (g_nLives < 0)
		if (m_fTimeEnd > 0)
		{
			m_fTimeEnd -= deltaTime;
		}
		else
		{
			this->GameOver();
		}

	//Xóa các danh sách các đối tượng vẽ và va chạm
	m_aObjectToDraw.clear();
	m_aObjectToCollision.clear();
	// Cập nhật vị trí viewport.
	CViewport::GetInstance()->SetPosition(m_pBill->GetPos());

	D3DXVECTOR2 vpPos = CViewport::GetInstance()->GetPosition();
	Box vpBox = { vpPos.x, vpPos.y, SCREEN_WIDTH, SCREEN_HEIGHT, 0.0f, 0.0f };
	m_pRootNode->GetObjectsInVP(vpBox, &m_aObjectToDraw);
	m_pCollisionNode->GetObjectsInVP(vpBox, &m_aObjectToCollision);
	m_pObjBoss->Update(deltaTime);

	switch (m_pObjBoss->GetTypeId())
	{
	case ID_BOSS_ONE:
		((CBossOne*)m_pObjBoss)->UpdateCollision(m_aObjectToCollision, deltaTime);
		if (!m_pObjBoss->m_bIsLive)
		{
			m_pSound->Stop();
			m_pSound = m_pResourcesManager->GetSound(ID_SOUND_BOSS_DEAD);
			m_pSound->Play();
			if (m_fTimeChange > 0)
				m_fTimeChange -= deltaTime;
			else
			{
				this->ChangeScene(deltaTime);
				if (m_bChanged)
					this->End();
			}
		}
		if (m_pBill->GetPos().x + m_pBill->GetBox().width / 2 > m_pObjBoss->GetBox().x)
		{
			m_pEnemyRun->Destroy();
			D3DXVECTOR2 posNew(m_pObjBoss->GetBox().x, m_pObjBoss->GetBox().y);
			D3DXVECTOR2 posA = CViewport::GetInstance()->GetPosition();
			if (posA.x < m_pObjBoss->GetBox().x)
				posA.x += VIEWPORT_VX * deltaTime;
			CViewport::GetInstance()->SetPosition(posA, false);
		}
		break;
	case ID_BOSS_THREE_DOOR:
		((CBossThreeDoor*)m_pObjBoss)->UpdateCollision(m_aObjectToCollision, deltaTime);
		if (m_bIsBossBorn)
		if (!m_pObjBoss->m_bIsLive)
		{
			m_pSound->Stop();
			m_pSound = m_pResourcesManager->GetSound(ID_SOUND_BOSS_DEAD);
			m_pSound->Play();
			if (m_fTimeChange > 0)
				m_fTimeChange -= deltaTime;
			else
			{
				this->ChangeScene(deltaTime);
				if (m_bChanged)
					this->End();
			}
		}
		if (m_pBill->GetPos().x + m_pBill->GetBox().width / 2 > m_pObjBoss->GetBox().x)
		{
			m_pSound->Stop();
			if (!m_bIsBossBorn)
			{
				m_bIsBossBorn = true;
				((CBossThreeDoor*)m_pObjBoss)->Born();
			}
			m_pEnemyRun->Destroy();
			D3DXVECTOR2 posNew(m_pObjBoss->GetBox().x, m_pObjBoss->GetBox().y);
			D3DXVECTOR2 posA = CViewport::GetInstance()->GetPosition();
			if (posA.x < m_pObjBoss->GetBox().x)
				posA.x += VIEWPORT_VX * deltaTime;
			CViewport::GetInstance()->SetPosition(posA, false);
		}
		break;
		case ID_BOSS_TWO:
			if (!m_pObjBoss->m_bIsLive)
			{
				m_pSound->Stop();
				m_pSound = m_pResourcesManager->GetSound(ID_SOUND_BOSS_DEAD);
				m_pSound->Play();
				if (m_fTimeChange > 0)
					m_fTimeChange -= deltaTime;
				else
				{
					this->ChangeScene(deltaTime);
					if (m_bChanged)
						this->End();
				}
			}
			if (m_pBill->GetPos().y + m_pBill->GetBox().height / 2 > m_pObjBoss->GetPos().y - SCREEN_HEIGHT / 4)
			{
				((CBossTwo*)m_pObjBoss)->Appear();
				D3DXVECTOR2 posNew(m_pObjBoss->GetBox().x, m_pObjBoss->GetPos().y + 100);
				D3DXVECTOR2 posA = CViewport::GetInstance()->GetPosition();
				if (posA.y < m_pObjBoss->GetBox().y + 100)
				posA.y += VIEWPORT_VY * deltaTime;
				CViewport::GetInstance()->SetPosition(posA, false);
				m_pEnemyRun->Destroy();
			}
			((CBossTwo*)m_pObjBoss)->UpdateCollision(m_aObjectToCollision, deltaTime);
			break;
	}

	
	

	for (CGameObject* tmpObj : m_aObjectToDraw)
	{
		tmpObj->Update(deltaTime);
		if (tmpObj->IsMoveableObject())
		{
			((CMoveableObject*)tmpObj)->UpdateCollision(m_aObjectToCollision, deltaTime);
			
		}
	}


	// Update đạn của Bill
	for (int i = 0; i < s_billBullets.size(); i++)
	{
		s_billBullets[i]->Update(deltaTime);
	}

	// Update đạn của Enemy
	for (int i = 0; i < s_enemyBullets.size(); i++)
	{
		s_enemyBullets[i]->Update(deltaTime);
		s_enemyBullets[i]->UpdateCollision(m_aObjectToCollision, deltaTime);
	}
	for (int i = 0; i < s_objsOutSideQuadTree.size(); i++)
	{
		s_objsOutSideQuadTree[i]->Update(deltaTime);

		if (s_objsOutSideQuadTree[i]->IsMoveableObject())
			((CMoveableObject*)s_objsOutSideQuadTree[i])->UpdateCollision(m_aObjectToCollision, deltaTime);
	}

	// Xóa các object đã chết các list.

	for (std::vector<CBullet*>::iterator it = s_billBullets.begin(); it != s_billBullets.end();)
	{
		if (!(*it)->IsLive())
		{
			it = s_billBullets.erase(it);
		}
		else
			++it;
	}

	for (std::vector<CBullet*>::iterator it = s_enemyBullets.begin(); it != s_enemyBullets.end();)
	{
		if (!(*it)->IsLive())
		{
			it = s_enemyBullets.erase(it);
		}
		else
			++it;
	}
	for (std::vector<CGameObject*>::iterator it = s_objsOutSideQuadTree.begin(); it != s_objsOutSideQuadTree.end();)
	{
		if (!(*it)->IsLive())
		{
			it = s_objsOutSideQuadTree.erase(it);
		}
		else
			++it;
	}


	m_pBill->Update(deltaTime);
	m_pEnemyRun->Update(deltaTime, m_aObjectToCollision);
	
	//output_print("%f:%f\n", s_enemyRun[1]->GetPos().x, s_enemyRun[1]->GetPos().y);

	for (int i = 0; i < MAX_ENEMIES; i++)
	{
		
		s_enemyRun[i]->Update(deltaTime);
		s_enemyRun[i]->UpdateCollision(m_aObjectToCollision, deltaTime);
	}

	//Update va chạm của Bill với các đối tượng trong quadtree va chạm
	m_pBill->UpdateCollision(m_aObjectToCollision, deltaTime);
	m_pShader = CGraphic::GetInstance()->texPS;
}

void CPlayState::Render()
{
	if (m_bFinished)
		return;
	if (m_fTimeLocal >= 0.2f)
	{
		m_pDevice->SetPixelShader(m_pShader);
	}

	for (std::vector<CGameObject*>::iterator it = m_aObjectToDraw.begin(); it != m_aObjectToDraw.end(); ++it)
	{
		if ((*it)->GetTypeId() != ID_STONE_FALLING_POINT)
		(*it)->Draw();
	}

	for (std::vector<CGameObject*>::iterator it = m_aObjectToCollision.begin(); it != m_aObjectToCollision.end(); ++it)
	{
		(*it)->Draw();
	}

	for (std::vector<CGameObject*>::iterator it = m_aObjectToDraw.begin(); it != m_aObjectToDraw.end(); ++it)
	{
		if ((*it)->GetTypeId() == ID_STONE_FALLING_POINT)
		{
		(*it)->Draw();
	}
	}
	
	if (m_pBill->GetChangingScene())
	{
		if (g_nCurentLvl == ID_LEVEL1 || g_nCurentLvl == ID_LEVEL3)
		{
			m_pBill->Draw();
			m_pObjBoss->Draw();
		}
		else
		{
			m_pObjBoss->Draw();
			m_pBill->Draw();
		}
	}
	else
	{
		m_pObjBoss->Draw();
		m_pBill->Draw();
	}

	for (int i = 0; i < s_billBullets.size(); i++)
	{
		s_billBullets[i]->Draw();
	}

	for (int i = 0; i < s_enemyBullets.size(); i++)
	{
		s_enemyBullets[i]->Draw();
	}

	for (int i = 0; i < MAX_ENEMIES; i++)
	{
		s_enemyRun[i]->Draw();
	}


	for (int i = 0; i < s_objsOutSideQuadTree.size(); i++)
	{
		s_objsOutSideQuadTree[i]->Draw();
	}

	if (g_nLives > 4)
	{
		for (int i = 0; i < 4; i++)
		{
			m_pLifeTexture->Draw(D3DXVECTOR2(20 + i * 25, 25));
}
	}
	else
	{
		for (int i = 0; i < g_nLives; i++)
		{
			m_pLifeTexture->Draw(D3DXVECTOR2(20 + i * 25, 25));
		}
	}

	if (g_nLives < 0)
		if (m_fTimeEnd > 0)
		{
			LPD3DXFONT* ppFont = CGraphic::GetInstance()->GetFontHandle();
			LPD3DXSPRITE ppSprite = CGraphic::GetInstance()->GetSpriteHandler();

			char info[50];
			RECT destSource;

			sprintf_s(info, "GAME");
			destSource.left = 25;
			destSource.top = 25;
			destSource.bottom = 40;
			destSource.right = 200;
			(*ppFont)->DrawTextA(ppSprite, info, strlen(info), &destSource, DT_LEFT, 0xFFFFFFFF);

			sprintf_s(info, "OVER");
			destSource.left = 25;
			destSource.top = 50;
			destSource.bottom = 65;
			destSource.right = 200;
			(*ppFont)->DrawTextA(ppSprite, info, strlen(info), &destSource, DT_LEFT, 0xFFFFFFFF);
		}
}

void CPlayState::End()
{
	m_pSound->Stop();
	m_bFinished = true;
	delete m_pNextState;
	g_nCurentLvl += 1;
	switch (g_nCurentLvl)
	{
	case ID_LEVEL1:
	case ID_LEVEL2:
	case ID_LEVEL3:
		m_pNextState = new CScoreState();
		break;
	case ID_END_GAME:
		m_pNextState = new CEndState();
		break;
	}
	m_bChanged = false;
	g_nCurrentBullet = m_pBill->GetCurrentBulletType();
	CGameStateManager::GetInstance()->ChangeState(m_pNextState);
}
	
void CPlayState::GameOver()
{
	m_pSound->Stop();
	m_bFinished = true;
	delete m_pNextState;
	m_pNextState = new CGameOverState();
	m_bChanged = false;
	CGameStateManager::GetInstance()->ChangeState(m_pNextState);
}

void CPlayState::ChangeScene(float timeFrame)
{
	CInput::GetInstance()->Unacquire();
	switch (g_nCurentLvl)
	{
	case ID_LEVEL1:
	case ID_LEVEL3:
		m_pBill->SetChangingScene(true);
		if (m_pBill->m_pos.x > CViewport::GetInstance()->GetPosition().x + SCREEN_WIDTH)
		{
			m_pBill->SetChangingScene(false);
			m_bChanged = true;
		}
		break;
	case ID_LEVEL2:
		m_pBill->SetChangingScene(true);
		if (m_pBill->m_pos.y > CViewport::GetInstance()->GetPosition().y - SCREEN_HEIGHT * 0.75f + 50)
		{
			m_pBill->SetChangingScene(false);
			m_bChanged = true;
		}
		break;
	}
}
